package com.junzhiit.nengji.app.service.impl;

import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.bainaeco.framework.util.EncryptMD5Util;
import com.junzhiit.nengji.app.service.SystemUserService;
import com.junzhiit.nengji.app.web.exception.InvalidLoginTokenException;
import com.junzhiit.nengji.app.web.exception.MobilePhoneCodeErrorException;
import com.junzhiit.nengji.app.web.exception.MobilePhoneCodeTimeoutException;
import com.junzhiit.nengji.app.web.exception.MobilePhoneHasUsedException;
import com.junzhiit.nengji.app.web.exception.PasswordNotMatchException;
import com.junzhiit.nengji.app.web.exception.SystemUserNotFoundException;
import com.junzhiit.nengji.app.web.util.Constants;
import com.junzhiit.nengji.app.web.util.OrderNumberUtils;
import com.junzhiit.nengji.app.web.util.ViewObjectUtil;
import com.junzhiit.nengji.app.web.util.rsa.RSACoder;
import com.junzhiit.nengji.app.web.util.tools.DIYTools;
import com.junzhiit.nengji.app.web.util.tools.KeyUtil;
import com.junzhiit.nengji.app.web.vo.DataTablesParamVO;
import com.junzhiit.nengji.app.web.vo.PhoneCodeVO;
import com.junzhiit.nengji.app.web.vo.ResultVO;
import com.junzhiit.nengji.app.web.vo.SystemUserAddVO;
import com.junzhiit.nengji.app.web.vo.SystemUserEditVO;
import com.junzhiit.nengji.app.web.vo.SystemUserListVO;
import com.junzhiit.nengji.app.web.vo.SystemUserRoleListVO;
import com.junzhiit.nengji.app.web.vo.SystemUserSessionVO;
import com.junzhiit.nengji.bo.SystemUserBO;
import com.junzhiit.nengji.dao.FunctionDAO;
import com.junzhiit.nengji.dao.RoleDAO;
import com.junzhiit.nengji.dao.RoleFunctionDAO;
import com.junzhiit.nengji.dao.SystemUserDAO;
import com.junzhiit.nengji.dao.SystemUserRoleDAO;
import com.junzhiit.nengji.dao.cache.RoleCacheDAO;
import com.junzhiit.nengji.dao.cache.SystemUserCacheDAO;
import com.junzhiit.nengji.dao.util.DIYKey;
import com.junzhiit.nengji.model.Function;
import com.junzhiit.nengji.model.Role;
import com.junzhiit.nengji.model.RoleFunction;
import com.junzhiit.nengji.model.SystemUser;
import com.junzhiit.nengji.model.SystemUserRole;
import com.junzhiit.nengji.model.enums.Is;
import com.junzhiit.nengji.model.enums.SystemUserStatus;
import com.junzhiit.nengji.model.enums.SystemUserType;

@Service
public class SystemUserServiceImpl extends BaseServiceImpl implements SystemUserService {

	@Value("${key.private}")
	private String PRIVATE_KEY_PATH;

	@Autowired
	private SystemUserDAO systemUserDAO;

	@Autowired
	private SystemUserCacheDAO systemUserCacheDAO;

	@Autowired
	private SystemUserRoleDAO systemUserRoleDAO;

	@Autowired
	private FunctionDAO functionDAO;

	@Autowired
	private RoleFunctionDAO roleFunctionDAO;

	@Autowired
	private RoleDAO roleDAO;

	@Autowired
	private RoleCacheDAO roleCacheDAO;

	@Override
	public Map<String, Object> findAll(DataTablesParamVO dtp, SystemUserListVO systemUserListVO) {
		SystemUserSessionVO systemUserSessionVO = systemUserCacheDAO
				.getHash(DIYKey.getSessionHashKey(systemUserListVO.getSessionId()), SystemUserSessionVO.class);

		SystemUser systemUser = new SystemUser();
		BeanUtils.copyProperties(systemUserListVO, systemUser);
		if(systemUserListVO.getPlatform() == null){
			systemUserListVO.setPlatform(Is.NO.toIntValue());
		}
		if (systemUserListVO.getPlatform().equals(systemUserSessionVO.getLoginType())) {
			systemUser.setSafetyLevel(systemUserSessionVO.getSafetyLevel());
		}
		systemUser.setSystemId(systemUserSessionVO.getSystemId());
		List<SystemUserBO> list = systemUserDAO.findAll(systemUser, dtp.getStart(), dtp.getLength());
		for (int i = 0; i < list.size(); i++) {
			SystemUserBO item = list.get(i);
			if (systemUserSessionVO.getSystemUserId().equals(item.getId())) {
				item.setIsCurrentAccount(Is.YES.toIntValue());
			} else {
				item.setIsCurrentAccount(Is.NO.toIntValue());
			}
		}

		int totalCount = systemUserDAO.getTotalCount(systemUser);
		return ViewObjectUtil.dataTables(list, dtp.getDraw(), totalCount);
	}

	@Override
	public Map<String, Object> findAllByPlatform(DataTablesParamVO dtp, SystemUserListVO systemUserListVO) {
		SystemUser systemUser = new SystemUser();
		BeanUtils.copyProperties(systemUserListVO, systemUser);
		List<SystemUserBO> list = systemUserDAO.findAll(systemUser, dtp.getStart(), dtp.getLength());
		int totalCount = systemUserDAO.getTotalCount(systemUser);
		return ViewObjectUtil.dataTables(list, dtp.getDraw(), totalCount);
	}

	@Override
	public ResultVO add(SystemUserAddVO systemUserAddVO) {
		ResultVO result = new ResultVO();

		if (!systemUserAddVO.getPassword().equals(systemUserAddVO.getConfirmPassword())) {
			throw new PasswordNotMatchException("密码不一致");
		}
		int mobilePhoneCount = systemUserDAO.getMobilePhoneCount(systemUserAddVO.getMobilePhone());
		if (mobilePhoneCount > 0) {
			throw new MobilePhoneHasUsedException("一个手机号码只能注册一个账号");
		}
		SystemUserSessionVO systemUserSessionVO = systemUserCacheDAO
				.getHash(DIYKey.getSessionHashKey(systemUserAddVO.getSessionId()), SystemUserSessionVO.class);
		SystemUser systemUser = new SystemUser();
		systemUser.setSystemId(systemUserSessionVO.getSystemId());
		systemUser.setSafetyLevel(systemUserSessionVO.getSafetyLevel().intValue() + 1);
		String password = EncryptMD5Util.getMD5(systemUserAddVO.getPassword());
		BeanUtils.copyProperties(systemUserAddVO, systemUser, new String[] { "confirmPassword" });
		systemUser.setPassword(password);
		systemUser.setStatus(SystemUserStatus.ACTIVE.toIntStatus());
		systemUser = systemUserDAO.insert(systemUser);
		systemUser.setPassword(null);

		if(systemUserAddVO.getRoleIds()!=null && systemUserAddVO.getRoleIds().size()>0){
			// addRole
			SystemUserRoleListVO systemUserRoleListVO = new SystemUserRoleListVO();
			systemUserRoleListVO.setSystemUserId(systemUser.getId());
			systemUserRoleListVO.setRoleIds(systemUserAddVO.getRoleIds());
			addSystemUserRole(systemUserRoleListVO);
		}

		result.setData(systemUser);
		return result;
	}

	@Override
	public ResultVO edit(String id, SystemUserEditVO systemUserEditVO) {
		ResultVO result = new ResultVO();

		SystemUser systemUser = systemUserDAO.findByMobilePhone(systemUserEditVO.getMobilePhone());
		if (systemUser != null && !systemUser.getId().equals(id)) {
			throw new MobilePhoneHasUsedException("该手机已经绑定其他账户");
		}

		systemUser.setId(id);
		BeanUtils.copyProperties(systemUserEditVO, systemUser);
		systemUserDAO.update(systemUser);
		systemUser.setPassword(null);

		// editRole
		SystemUserRoleListVO systemUserRoleListVO = new SystemUserRoleListVO();
		systemUserRoleListVO.setSystemUserId(id);
		if(systemUserEditVO.getRoleIds()!=null && systemUserEditVO.getRoleIds().size()>0){
			systemUserRoleListVO.setRoleIds(systemUserEditVO.getRoleIds());
			addSystemUserRole(systemUserRoleListVO);
		}

		result.setData(systemUser);
		return result;
	}

	@Override
	public ResultVO checkPhone(String mobilePhone) {
		ResultVO result = new ResultVO();
		int mobilePhoneCount = systemUserDAO.getMobilePhoneCount(mobilePhone);
		if (mobilePhoneCount > 0) {
			throw new MobilePhoneHasUsedException("手机号码已被注册");
		}
		return result;
	}

	@Override
	public int addSystemUserRole(SystemUserRoleListVO systemUserRoleListVO) {
		List<SystemUserRole> systemUserRoles = new ArrayList<SystemUserRole>();
		for (String roleId : systemUserRoleListVO.getRoleIds()) {
			SystemUserRole systemUserRole = new SystemUserRole();
			systemUserRole.setRoleId(roleId);
			systemUserRole.setSystemUserId(systemUserRoleListVO.getSystemUserId());
			systemUserRoles.add(systemUserRole);
		}

		systemUserRoleDAO.deleteSystemUserRole(systemUserRoleListVO.getSystemUserId());
		return systemUserRoleDAO.batchInsert(systemUserRoles);
	}

	@Override
	public ResultVO initPower(SystemUserAddVO systemUserAddVO) {
		ResultVO result = new ResultVO();

		// 添加用户
		if (!systemUserAddVO.getPassword().equals(systemUserAddVO.getConfirmPassword())) {
			throw new PasswordNotMatchException("密码不一致");
		}
		int mobilePhoneCount = systemUserDAO.getMobilePhoneCount(systemUserAddVO.getMobilePhone());
		if (mobilePhoneCount > 0) {
			throw new MobilePhoneHasUsedException("一个手机号码只能注册一个账号");
		}
		SystemUser systemUser = new SystemUser();
		systemUser.setSafetyLevel(0);
		String password = EncryptMD5Util.getMD5(systemUserAddVO.getPassword());
		BeanUtils.copyProperties(systemUserAddVO, systemUser, new String[] { "confirmPassword" });
		systemUser.setPassword(password);
		systemUser.setStatus(SystemUserStatus.ACTIVE.toIntStatus());
		systemUser = systemUserDAO.insert(systemUser);

		// 添加角色
		Role role = new Role();
		role.setName("系统管理员");
		Long index = roleCacheDAO.incr(DIYKey.getRoleCodeStringKey());
		String code = OrderNumberUtils.getSystemCode(OrderNumberUtils.ROLE_NUMBER_PREFIX, index.intValue());
		role.setCode(code);
		role.setPlatform(SystemUserType.INTERNAL.toIntStatus());
		role.setIsSys(Is.YES.toIntValue());
		role.setIsCommon(Is.YES.toIntValue());
		Role newRole = roleDAO.insert(role);

		// 添加角色功能
		List<RoleFunction> roleFunctions = new ArrayList<RoleFunction>();
		List<Function> functions = functionDAO.findByPlatform(SystemUserType.INTERNAL.toIntStatus());
		for (Function function : functions) {
			RoleFunction rolefunction = new RoleFunction();
			rolefunction.setFunctionId(function.getId());
			rolefunction.setRoleId(newRole.getId());
			roleFunctions.add(rolefunction);
		}
		roleFunctionDAO.batchInsert(roleFunctions);

		// 添加用户角色
		SystemUserRole systemUserRole = new SystemUserRole();
		systemUserRole.setSystemUserId(systemUser.getId());
		systemUserRole.setRoleId(newRole.getId());
		systemUserRoleDAO.insert(systemUserRole);

		return result;
	}

	@Override
	public ResultVO editUser(SystemUserEditVO systemUserEditVO) {
		ResultVO result = new ResultVO();
		SystemUserSessionVO systemUserSessionVO = systemUserCacheDAO
				.getHash(DIYKey.getSessionHashKey(systemUserEditVO.getSessionId()), SystemUserSessionVO.class);
		SystemUser systemUser = systemUserDAO.query(systemUserSessionVO.getSystemUserId());

		// RSA decoder.
		KeyPair KeyPair = KeyUtil.keyPair(PRIVATE_KEY_PATH);
		String systemUserToken = "", systemUserTokenUrl = "";
		try {
			systemUserTokenUrl = DIYTools.URLDecoder(systemUserEditVO.getSystemUserToken());
			systemUserToken = RSACoder.decrypt(systemUserTokenUrl, KeyPair.getPrivate());
		} catch (Exception e) {
			throw new InvalidLoginTokenException("Invalid login token.");
		}
		Map<String, String> content = DIYTools.splitForm(systemUserToken);
		String mobilePhone = content.get("mobilePhone");
		String oldPassword = content.get("oldPassword");
		String password = content.get("password");
		String name = content.get("name");
		String email = content.get("email");

		// 原密码错误
		if (oldPassword != null) {
			String MD5oldPassword = EncryptMD5Util.getMD5(oldPassword);
			if (!systemUser.getPassword().equals(MD5oldPassword)) {
				throw new PasswordNotMatchException("原密码错误");
			}
		}

		// 不更换手机
		PhoneCodeVO oldPhoneCode = systemUserCacheDAO.getHash(DIYKey.getMobilePhoneCodeKey(systemUser.getMobilePhone()),
				PhoneCodeVO.class);
		if (StringUtils.isNoneBlank(systemUserEditVO.getOldPhoneCode())
				&& !oldPhoneCode.getCode().equals(systemUserEditVO.getOldPhoneCode())) {
			throw new MobilePhoneCodeErrorException("验证码不一致");
		}

		if (StringUtils.isNoneBlank(systemUserEditVO.getOldPhoneCode())
				&& oldPhoneCode.getTimestamp() < new Date().getTime()) {
			throw new MobilePhoneCodeTimeoutException("验证码已过期");
		}
		// 若更换手机
		if (systemUserEditVO.getIsUpdateMobilePhone()!=null && systemUserEditVO.getIsUpdateMobilePhone() == Is.YES.toIntValue()) {
			PhoneCodeVO newPhoneCode = systemUserCacheDAO
					.getHash(DIYKey.getMobilePhoneCodeKey(systemUserEditVO.getMobilePhone()), PhoneCodeVO.class);
			SystemUser user = systemUserDAO.findByMobilePhone(systemUserEditVO.getMobilePhone());
			if (!newPhoneCode.getCode().equals(systemUserEditVO.getNewPhoneCode())) {
				throw new MobilePhoneCodeErrorException("验证码不一致");
			}

			if (newPhoneCode.getTimestamp() < new Date().getTime()) {
				throw new MobilePhoneCodeTimeoutException("验证码已过期");
			}
			if (user != null && !user.getId().equals(systemUser.getId())) {
				throw new MobilePhoneHasUsedException("该手机已经绑定其他账户");
			}
		}
		if (systemUserEditVO.getIsUpdatePassword()!=null && systemUserEditVO.getIsUpdatePassword() == Is.YES.toIntValue()) {
			String MD5password = EncryptMD5Util.getMD5(password);
			systemUser.setPassword(MD5password);
		}
		
		if(StringUtils.isNotBlank(mobilePhone)){
			systemUser.setMobilePhone(mobilePhone);
		}
		if(StringUtils.isNotBlank(name)){
			systemUser.setName(name);
		}
		if(StringUtils.isNotBlank(email)){
			systemUser.setEmail(email);
		}
		if(systemUserEditVO.getGender()!=null){
			systemUser.setGender(systemUserEditVO.getGender());
		}

		if (systemUser.getIsUpdatePassword() != Is.YES.toIntValue()) {
			systemUser.setIsUpdatePassword(systemUserEditVO.getIsUpdatePassword());
		}

		// 移除cookies
		Map<String, String> map = new HashMap<String, String>();
		map.put(Constants.ACCESS_TOKEN_SESSION, systemUserSessionVO.getSessionId());
		map.put(Constants.SYSTEM_ID, systemUserSessionVO.getSystemId());
		map.put(Constants.LOGIN_TYPE, systemUserSessionVO.getLoginType().toString());

		result.setData(map);

		systemUserDAO.update(systemUser);
		// 若修改手机号（账号）或密码则需要重新登陆
		if (systemUserEditVO.getIsUpdateMobilePhone()!=null && systemUserEditVO.getIsUpdateMobilePhone() == Is.YES.toIntValue()
				|| systemUserEditVO.getIsUpdatePassword() == Is.YES.toIntValue()) {
			String key = DIYKey.getSessionHashKey(systemUserEditVO.getSessionId());
			systemUserCacheDAO.del(key);
		}

		return result;
	}

	@Override
	public SystemUser findBySessionId(String sessionId) {
		SystemUserSessionVO systemUserSessionVO = systemUserCacheDAO.getHash(DIYKey.getSessionHashKey(sessionId),
				SystemUserSessionVO.class);
		SystemUser systemUser = systemUserDAO.query(systemUserSessionVO.getSystemUserId());
		if (systemUser == null) {
			throw new SystemUserNotFoundException("该用户不存在！");
		}
		systemUser.setPassword(null);
		return systemUser;
	}
}
